// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: authentication-free shared key and token derivation between clients
// feature: discovery support client and server
// ------------------------------------------------------------------

#ifndef SRC_CPP_SECURITY_AUTHENTICATION_PKIDH_H_
#define SRC_CPP_SECURITY_AUTHENTICATION_PKIDH_H_

#include <edds/rtps/security/authentication/Authentication.h>
#include <edds/rtps/attributes/PropertyPolicy.h>
#include <security/authentication/PKIHandshakeHandle.h>
#include <memory>
#include <security/artifact_providers/Pkcs11Provider.hpp>

#if VBSAUTH
#include "VBSAuthManager.h"
#endif

namespace evbs {
namespace ertps {
namespace rtps {
namespace security {

class PKIDH : public Authentication {
 public:
    ValidationResult_t validate_local_identity(IdentityHandle** local_identity_handle, GUID_t& adjusted_participant_key,
                                               const uint32_t domain_id,
                                               const RTPSParticipantAttributes& participant_attr,
                                               const GUID_t& candidate_participant_key,
                                               SecurityException& exception) override;

    ValidationResult_t validate_remote_identity(IdentityHandle** remote_identity_handle,
                                                const IdentityHandle& local_identity_handle,
                                                const IdentityToken& remote_identity_token,
                                                const GUID_t& remote_participant_key,
                                                SecurityException& exception) override;

    ValidationResult_t begin_handshake_request(HandshakeHandle** handshake_handle,
                                               HandshakeMessageToken** handshake_message,
                                               const IdentityHandle& initiator_identity_handle,
                                               IdentityHandle& replier_identity_handle,
                                               const CDRMessage_t& cdr_participant_data,
                                               SecurityException& exception) override;

    ValidationResult_t begin_handshake_reply(HandshakeHandle** handshake_handle,
                                             HandshakeMessageToken** handshake_message_out,
                                             HandshakeMessageToken&& handshake_message_in,
                                             IdentityHandle& initiator_identity_handle,
                                             const IdentityHandle& replier_identity_handle,
                                             const CDRMessage_t& cdr_participant_data,
                                             SecurityException& exception) override;

    ValidationResult_t process_handshake(HandshakeMessageToken** handshake_message_out,
                                         HandshakeMessageToken&& handshake_message_in,
                                         HandshakeHandle& handshake_handle, SecurityException& exception) override;

    std::shared_ptr<SecretHandle> get_shared_secret(const HandshakeHandle& handshake_handle,
                                                    SecurityException& exception) const override;

    bool set_listener(AuthenticationListener* listener, SecurityException& exception) override;

    bool get_identity_token(IdentityToken** identity_token, const IdentityHandle& handle,
                            SecurityException& exception) override;

    bool return_identity_token(IdentityToken* token, SecurityException& exception) override;

    bool return_handshake_handle(HandshakeHandle* handshake_handle, SecurityException& exception) override;

    IdentityHandle* get_identity_handle(SecurityException& exception) override;

    bool return_identity_handle(IdentityHandle* identity_handle, SecurityException& exception) override;

    bool return_sharedsecret_handle(std::shared_ptr<SecretHandle>& sharedsecret_handle,
                                    SecurityException& exception) const override;

    bool set_permissions_credential_and_token(IdentityHandle& identity_handle,
                                              PermissionsCredentialToken& permissions_credential_token,
                                              SecurityException& ex) override;

    bool get_authenticated_peer_credential_token(PermissionsCredentialToken** token,
                                                 const IdentityHandle& identity_handle,
                                                 SecurityException& exception) override;

    bool return_authenticated_peer_credential_token(PermissionsCredentialToken* token, SecurityException& ex) override;

    bool check_guid_comes_from(IdentityHandle* identity_handle, const GUID_t& adjusted,
                               const GUID_t& original) override;

    ValidationResult_t begin_fake_handshake_reply(HandshakeHandle** handshake_handle,
                                                  IdentityHandle& initiator_identity_handle,
                                                  const IdentityHandle& replier_identity_handle,
                                                  const CDRMessage_t& cdr_participant_data,
                                                  SecurityException& exception) override;

    ValidationResult_t process_fake_handshake(uint32_t auth_status, const std::vector<uint8_t>& shared_key,
                                              HandshakeHandle& handshake_handle, SecurityException& exception) override;

    std::unique_ptr<detail::Pkcs11Provider> pkcs11_provider;

#if VBSAUTH
    static vbs::security::auth::VBSAuthManager& vbsauth;
    bool is_use_vbsauth;
#endif

    static EVP_PKEY* coverVectortoPem_base64(const std::vector<unsigned char>& key, SecurityException& exception);
    static void generate_secret_P(GUID_t guidA, GUID_t guidB, std::vector<uint8_t>& data);
    static bool ed25519_verify_message(EVP_PKEY* pkey, const std::vector<uint8_t>& message,
                                       const std::vector<unsigned char>& sign_data, SecurityException& exception);
    static bool mvbs_hmac_message(const std::vector<uint8_t>& pkey, const std::vector<uint8_t>& message,
                                  std::vector<uint8_t>& sign_data, SecurityException& exception);
    static bool mvbs_hmac_verify_message(const std::vector<uint8_t>& pkey, const std::vector<uint8_t>& message,
                                         const std::vector<uint8_t>& sign_data, SecurityException& exception);
    static bool mvbs_hmac_sha256(const unsigned char* data, const size_t length, std::vector<uint8_t>& mac,
                                 SecurityException& exception);

 private:
    ValidationResult_t process_handshake_request(HandshakeMessageToken** handshake_message_out,
                                                 HandshakeMessageToken&& handshake_message_in,
                                                 PKIHandshakeHandle& handshake_handle, SecurityException& exception);

    ValidationResult_t process_handshake_reply(HandshakeMessageToken** handshake_message_out,
                                               HandshakeMessageToken&& handshake_message_in,
                                               PKIHandshakeHandle& handshake_handle, SecurityException& exception);
    ValidationResult_t process_handshake_request_mvbs(HandshakeMessageToken** handshake_message_out,
                                                      HandshakeMessageToken&& handshake_message_in,
                                                      PKIHandshakeHandle& handshake_handle,
                                                      SecurityException& exception);

    ValidationResult_t process_handshake_reply_mvbs(HandshakeMessageToken** handshake_message_out,
                                                    HandshakeMessageToken&& handshake_message_in,
                                                    PKIHandshakeHandle& handshake_handle, SecurityException& exception);

    std::shared_ptr<SecretHandle> generate_sharedsecret(EVP_PKEY* private_key, EVP_PKEY* public_key,
                                                        SecurityException& exception) const;

    ValidationResult_t process_fake_handshake_request(const std::vector<uint8_t>& shared_key,
                                                      PKIHandshakeHandle& handshake_handle,
                                                      SecurityException& exception);

    ValidationResult_t process_fake_handshake_reply(const std::vector<uint8_t>& shared_key,
                                                    PKIHandshakeHandle& handshake_handle, SecurityException& exception);

    std::shared_ptr<SecretHandle> generate_fake_sharedsecret(const std::vector<uint8_t>& SharedKey,
                                                             SecurityException& exception) const;

    std::shared_ptr<SecretHandle> generate_sharedsecret_mvbs();

    // void record_mcoreinfo(IdentityHandle& replier_identity_handle, bool _ismvbs_sec);
};

}  // namespace security
}  // namespace rtps
}  // namespace ertps
}  // namespace evbs

#endif  // SRC_CPP_SECURITY_AUTHENTICATION_PKIDH_H_
